# -*- coding: utf-8 -*- #
"""
Time                2023/09/20 19:03
Author:             panyihang
Email               2020200824@ruc.edu.cn
File                main.py
Description:
"""
from clogger import logger
from fastapi import FastAPI
from app.routers import health
from conf.settings import YAML_CONFIG
from sysom_utils import CmgPlugin, SysomFramework
import traceback
import sys,os,json
sys.path.append("%s/lib"%(os.path.dirname(os.path.abspath(__file__))))
import time
import datetime
from datetime import date, datetime, timedelta
import requests
from metric_reader import MetricReader, dispatch_metric_reader,RangeQueryTask

import pandas as pd
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
import adtk
from adtk.data import validate_series
from adtk.visualization import plot
from adtk.transformer import RollingAggregate
from adtk.transformer import DoubleRollingAggregate
from adtk.detector import PersistAD
from adtk.detector import LevelShiftAD
from adtk.detector import SeasonalAD
from adtk.detector import AutoregressionAD
import traceback
from sysom_monitor_item import sysommonit_items,sysommonit_items_general_name
from conf.settings import YAML_CONFIG,service_config
import uuid

app = FastAPI()

app.include_router(health.router, prefix="/api/v1/metric_anomaly_detection/health")

metric_reader = dispatch_metric_reader("prometheus://localhost:9090")

def pull_monidata(start_time,end_time):
    retdict = []
    try:
        for item in service_config.metric_detect_items.metric_items:
            if service_config.metric_detect_items.metric_items[item] is not True or item not in sysommonit_items_general_name:
                continue
            else:
                sp_item = sysommonit_items_general_name[item]
            if "sysom" not in sp_item and "sysak" not in sp_item:
                continue
            if "-" in sp_item:
                tag_list = sp_item.split('-')
                sysom_tag = tag_list[0]
            if sysom_tag not in sysommonit_items:
                continue
            if len(tag_list)-1 > len(sysommonit_items[sysom_tag]):
                continue
            tag_value = tag_list[1:]
            tag_name = []
            for i in range(len(sysommonit_items[sysom_tag])):
                if sysommonit_items[sysom_tag][i] != "instance":
                    tag_name.append(sysommonit_items[sysom_tag][i])

            task = RangeQueryTask(sysom_tag, start_time, end_time).append_wildcard_filter("instance", "*")
            ret_tmp = metric_reader.range_query([task])
            if len(ret_tmp.data) > 0:
                for i in range(len(ret_tmp.data)):
                    match_cnt = 0
                    if "labels" in ret_tmp.data[i].to_dict():
                        item_labels = ret_tmp.data[i].to_dict()["labels"]
                        for j in range(len(tag_name)):
                            if tag_name[j] not in item_labels:
                                continue
                            for k in range(len(tag_value)):
                                if item_labels[tag_name[j]] == tag_value[k]:
                                    match_cnt += 1
                    else:
                        continue
                    if match_cnt == len(tag_value):
                        rettmp = ret_tmp.data[i].to_dict()
                        rettmp["general_name"] = item
                        retdict.append(rettmp)
    except Exception as e:
        traceback.print_exc()
        logger.exception(e)
        pass
    return retdict

def sysom_alarm(warndict):
    try:
        SysomFramework.alarm({
            "alert_id": str(uuid.uuid4()),
            "instance": warndict["instance"],
            "alert_item": warndict["alert_item"],
            "alert_category": warndict["alert_category"],
            "alert_source_type": warndict["alert_source_type"],
            "alert_time": warndict["alert_time"],
            "status": "FIRING",
            "labels": {},
            "annotations": {
                "summary": warndict["annotations"]["summary"]
            }
        })
    except Exception as e:
        traceback.print_exc()
        logger.exception(e)

def detect_spike(s):
    retdict = {"instance":"","alert_item":"","alert_category":"MONITOR","alert_source_type":"grafana",
                "alert_time":"","annotations":{"summary":""},"origin_alert_data": {},"warn_on":False}
    try:
        items_list = []
        for i in s['values']:
            items_list.append([i[0],i[1]])
        for i in range(len(items_list)):
            items_list[i][0] = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(items_list[i][0]))
        df = pd.DataFrame(items_list)
        df.columns = ["timestamp","values"]
        df = df.set_index("timestamp")
        df.index = pd.DatetimeIndex(df.index)
        df = validate_series(df)
        spikes = PersistAD(c=3, side='positive').fit_detect(df)
        sp = np.array(spikes.reset_index())
        warn_on = 0
        warn_max_index = 0
        for j in range(len(sp)):
            if sp[j][1] == 1.0:
                warn_max_index = j
                warn_on = 1
        if warn_on == 1:
            retdict["warn_on"] = True
            retdict["instance"] = s["labels"]["instance"]
            if ":" in retdict["instance"]:
                retdict["instance"] = retdict["instance"].split(":")[0]
            retdict["alert_item"] = s["general_name"]
            retdict["alert_time"] = s['values'][warn_max_index][0]
            origin_alert_data = {}
            for j in s['values']:
                origin_alert_data[j[0]] = j[1]
            retdict["origin_alert_data"] = origin_alert_data
            retdict["annotations"]["summary"] = "指标%s在%s时间点存在突增"%(retdict["alert_item"],sp[warn_max_index][0])
            sysom_alarm(retdict)
    except Exception as e:
        traceback.print_exc()
        logger.exception(e)
        pass
    return retdict

def metric_detect_loop():
    try:
        detect_on = service_config.metric_detect_items.detect_on
        detect_items = service_config.metric_detect_items.items
        while(detect_on is True):
            now_time = time.time()
            retdata = pull_monidata(now_time-600, now_time)
            for  i in retdata:
                detect_spike(i)
            time.sleep(service_config.metric_detect_items.detect_interval)

    except Exception as e:
        traceback.print_exc()
        logger.exception(e)

#############################################################################
# Write your API interface here, or add to app/routes
#############################################################################


def init_framwork():
    SysomFramework\
        .init(YAML_CONFIG) \
        .load_plugin_cls(CmgPlugin) \
        .start()
    logger.info("SysomFramework init finished!")


@app.on_event("startup")
async def on_start():
    metric_detect_loop()
    init_framwork()
    
    #############################################################################
    # Perform some microservice initialization operations over here
    #############################################################################


@app.on_event("shutdown")
async def on_shutdown():
    pass
